還記得前幾天講的類別嗎?如果我有個 Person
類別但它又有點特別,就好比在學校裡面有學生,有老師,有校長等等,這些身分可都會具有不同權限 (或是我們說權利義務)。那如果我要把這些全部都寫在同一個類別內似乎有點太肥大而且難以控管,萬一今天學生拿著校長的萬用鑰匙開了老師的考卷解答櫃那豈不是出大事!但如果我今天把校長、老師、學生等各種學校職員都分開設定,想必會有很多重複的程式碼散落在各處吧,每個人都至少會有姓名、性別、年齡等等。這時候繼承就可以派上用場了,跟法律上聽到的繼承很像,你父母有的,你會有,你也可以跟你父母不一樣。今天讓我們初步帶出繼承這個概念,接下來幾天介紹的都會跟它息息相關喔!
繼承允許一個類別繼承另一個類別的變數與函式。在 Kotlin 中,一個類別可以使用 :
符號,後面跟著父類別的名稱,來實現繼承。以下是 Kotlin 中繼承的基本語法:
open class 父類別 {
// 父類別的屬性和方法
}
class 子類別 : 父類別() {
// 子類別的屬性和方法
}
這裡我們會需要注意一個小細節,在 Kotlin 裡面預設的類別 (class
) 都是 final
(可以先理解成最終型態或是末代) 也就是說它沒有辦法直接被繼承,所以我們需要在前面加上 open
字樣告訴 Kotlin 我不是末代喔!
當你在 Kotlin 中繼承一個類別時,父類別的主建構子會被自動調用。如果父類別的建構子有參數,你需要在宣告子類別時將這些參數傳遞給父類別的建構子。
open class Person(val name: String, val age: Int)
class Student(name: String, age: Int, val studentId: String) : Person(name, age)
在這個例子中,Student
類別繼承自 Person
類別。 Person
類別的 name
和 age
參數在創建 Student
物件時被傳遞給它的建構子。
“你也可以跟你父母不一樣”,這句話在 Kotlin 中,你可以使用 override
關鍵字在子類別中覆寫父類別的函式與變數。
open class Shape {
open fun draw() {
println("Drawing a shape")
}
open val name = "default"
}
class Circle : Shape() {
override fun draw() {
println("Drawing a circle")
}
override val name = "Circle"
}
fun main() {
val circle = Circle()
println(circle.name)
}
在這個例子中,Circle
類別覆寫了 Circle
類別的 draw()
方法。
在 Kotlin 中,存取修飾符(public
、protected
、internal
、private
)在繼承的成員中的作用與它們在其他成員中的作用相同。默認的可見性是 public
。你也可以使用 protected
修飾符來使成員在它的子類別中可見。
open class Shape {
open fun draw() {
println("Drawing a shape")
}
open protected val name = "default"
fun getShapeName(): String {
return name
}
}
class Circle : Shape() {
override fun draw() {
println("Drawing a circle")
}
override val name = "Circle"
fun getCircleName(): String {
return name
}
}
fun main() {
val shape = Shape()
println(shape.getShapeName()) // default
val circle = Circle()
println(circle.getShapeName()) // Circle
println(circle.getCircleName()) // Circle
// println(circle.name) // Cannot access 'name': it is protected in 'Circle'
}